#include "grflib_stdafx.h"
#include "../include/TextureHelper.h"
#include <ImgHelper.h>
#include "../include/D3D10Engine.h"
#include "../include/PointerCast.h"

namespace grflib { namespace engine { namespace aux { namespace texture_helper {

HRESULT Create2DTextureFromFile(const char *textureName, 
    const TCHAR *fileName,
    TextureSpec::BindTarget bindTarget,
    TextureSpec::TextureUsage usage,
    boost::shared_ptr<grflib::engine::core::CTexture2D> &pTexture)
{
    _TSTRING fullPath;
    _TSTRING partialPath(fileName);

    using namespace grflib::engine::core;

    HRESULT hr;
    V_RETURN(_SearchPaths.Complete(partialPath, fullPath));
    w32lib::ImagePtr imgPtr = w32lib::image_helper::LoadImageFromDisk(fullPath);
    if (w32lib::BPC_U8 == imgPtr->GetPixelFormat() && 24 == imgPtr->GetBPP())
    {
        if (!imgPtr->m_ptr.pU8->AddChannel(1, 255))
        {
            W32ERR(_T("Failed to insert alpha channel to 24bit RGB image!"));
            return E_FAIL;
        }
    }

    pTexture.reset( new CTexture2D(usage, bindTarget, imgPtr) );
    if (!pTexture)
    {
        W32ERR(_T("Failed to create texture from file!"));
        return E_FAIL;
    }
    if (!_ResrcMan.AddObj(textureName, core::cast::IResourceCast(pTexture)))
    {
        W32ERR(_T("Failed to add texture to resource manager!"));
        return E_FAIL;
    }

    return S_OK;
}

HRESULT CreateCubeTextureFromStripFile(const char *textureName, 
    const TCHAR *fileName,
    TextureSpec::BindTarget bindTarget,
    TextureSpec::TextureUsage usage,
    boost::shared_ptr<grflib::engine::core::CTextureCube> &pTexture)
{
    _TSTRING fullPath;
    _TSTRING partialPath(fileName);

    using namespace grflib::engine::core;

    HRESULT hr;
    V_RETURN(_SearchPaths.Complete(partialPath, fullPath));
    w32lib::ImagePtr imgPtr = w32lib::image_helper::LoadImageFromDisk(fullPath);
    if (w32lib::BPC_U8 == imgPtr->GetPixelFormat() && 24 == imgPtr->GetBPP())
    {
        if (!imgPtr->m_ptr.pU8->AddChannel(1, 255))
        {
            W32ERR(_T("Failed to insert alpha channel to 24bit RGB image!"));
            return E_FAIL;
        }
    }

    pTexture.reset( new CTextureCube(usage, bindTarget, imgPtr) );
    if (!pTexture)
    {
        W32ERR(_T("Failed to create texture from file!"));
        return E_FAIL;
    }
    if (!_ResrcMan.AddObj(textureName, core::cast::IResourceCast(pTexture)))
    {
        W32ERR(_T("Failed to add texture to resource manager!"));
        return E_FAIL;
    }

    return S_OK;
}

HRESULT Create3DTextureFromVStripFile(const char *textureName, 
    const TCHAR *fileName,
    const UINT sliceHeight,
    TextureSpec::BindTarget bindTarget,
    TextureSpec::TextureUsage usage,
    boost::shared_ptr<grflib::engine::core::CTexture3D> &pTexture)
{
    if (0 == sliceHeight)
    {
        W32ERR(_T("Invalid volume texture slice height!"));
        return E_INVALIDARG;
    }

    _TSTRING fullPath;
    _TSTRING partialPath(fileName);
    using namespace grflib::engine::core;

    HRESULT hr;
    V_RETURN(_SearchPaths.Complete(partialPath, fullPath));
    w32lib::ImagePtr imgPtr = w32lib::image_helper::LoadImageFromDisk(fullPath);
    if (w32lib::BPC_U8 == imgPtr->GetPixelFormat() && 24 == imgPtr->GetBPP())
    {
        if (!imgPtr->m_ptr.pU8->AddChannel(1, 255))
        {
            W32ERR(_T("Failed to insert alpha channel to 24bit RGB image!"));
            return E_FAIL;
        }
    }

    const UINT width = imgPtr->GetWidth();
    const UINT nSlice = imgPtr->GetHeight() / sliceHeight;
    DXGI_FORMAT format = texture_format::Mapping(imgPtr);
    
    UINT bufferLength = imgPtr->BytesPerLine() * imgPtr->GetHeight();
    boost::shared_array<char> tmpData( new char[bufferLength] );
    if (!tmpData)
    {
        imgPtr->Delete();
        W32ERR(_T("Failed to allocate memory for volume texture!"));
        return E_FAIL;
    }
    memcpy(tmpData.get(), imgPtr->GetBuffer(), bufferLength);
    imgPtr->Delete();

    pTexture.reset(new CTexture3D(usage, 
        bindTarget, 
        tmpData, 
        width, 
        sliceHeight, 
        nSlice, 
        format));

    if (!pTexture)
    {
        W32ERR(_T("Failed to create texture from file!"));
        return E_FAIL;
    }
    if (!_ResrcMan.AddObj(textureName, core::cast::IResourceCast(pTexture)))
    {
        W32ERR(_T("Failed to add texture to resource manager!"));
        return E_FAIL;
    }
    
    return S_OK;
}


}}}} //namespaces